using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Web;

namespace NS3Library
{
    public abstract class AbstractS3Bucket : IS3Bucket
    {
        private readonly string _name;
        private readonly S3LocationConstraint _locationConstraint = S3LocationConstraint.None;
        private readonly string _prefix;
        private readonly int _maxKeys = int.MinValue;
        private readonly string _marker;
        private readonly string _delimiter;
        private readonly S3Acl _aclHeader;
        private readonly bool _isTruncated;
        private readonly IEnumerable<IS3ObjectKey> _s3ObjectKeys = new IS3ObjectKey[0];

        internal AbstractS3Bucket(string name)
        {
            Validate(name);
            _name = name;
        }

        internal AbstractS3Bucket(string name, S3LocationConstraint locationConstraint, S3Acl acl)
            : this(name)
        {
            _locationConstraint = locationConstraint;
            _aclHeader = acl;
        }

        internal AbstractS3Bucket(string name, string prefix, int maxKeys, string marker, string delimiter)
            : this(name)
        {
            _prefix = prefix;
            _maxKeys = maxKeys;
            _marker = marker;
            _delimiter = delimiter;
        }

        internal AbstractS3Bucket(string name, string prefix, int maxKeys, string marker, string delimiter,
                                  bool isTruncated,
                                  IEnumerable<IS3ObjectKey> keys)
            : this(name, prefix, maxKeys, marker, delimiter)
        {
            _isTruncated = isTruncated;
            _s3ObjectKeys = keys;
        }

        public string Name
        {
            get { return _name; }
        }

        public S3LocationConstraint LocationConstraint
        {
            get { return _locationConstraint; }
        }

        public string Prefix
        {
            get { return _prefix; }
        }

        public int MaxKeys
        {
            get { return _maxKeys; }
        }

        public string Marker
        {
            get { return _marker; }
        }

        public string Delimiter
        {
            get { return _delimiter; }
        }

        public S3Acl AclHeader
        {
            get { return _aclHeader; }
        }

        public bool IsTruncated
        {
            get { return _isTruncated; }
        }

        public IEnumerable<IS3ObjectKey> S3ObjectKeys
        {
            get { return _s3ObjectKeys; }
        }

        private static void Validate(string name)
        {
            if (!Regex.IsMatch(name, "^[a-z0-9]{1}[a-z0-9-.]{2,62}$"))
                throw new S3NamingException();
            else if (Regex.IsMatch(name, @"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"))
                throw new S3NamingException();
            else if (name.StartsWith("-") || name.StartsWith(".") || name.EndsWith("-"))
                throw new S3NamingException();
            else if (Regex.IsMatch(name, @"\.-|-\."))
                throw new S3NamingException();
        }

        public IEnumerable<string> Parameters()
        {
            var parameters = new List<string>();
            if (!string.IsNullOrEmpty(_prefix))
                parameters.Add("prefix=" + HttpUtility.UrlEncode(_prefix));
            if (_maxKeys != int.MinValue)
                parameters.Add("max-keys=" + HttpUtility.UrlEncode(_maxKeys.ToString(CultureInfo.InvariantCulture)));
            if (!string.IsNullOrEmpty(_marker))
                parameters.Add("marker=" + HttpUtility.UrlEncode(_marker));
            if (!string.IsNullOrEmpty(_delimiter))
                parameters.Add("delimiter=" + HttpUtility.UrlEncode(_delimiter));
            parameters.Sort();
            return parameters;
        }

        public NameValueCollection Headers()
        {
            var headers = new NameValueCollection();
            if (_aclHeader != null)
                headers.Add(S3Acl.AmazonAclHeaderName, _aclHeader.ToString());
            return headers;
        }
    }
}